package top.v5it.japi.plus.support.lock;

import cn.hutool.core.util.NumberUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import top.v5it.japi.plus.support.LuaScriptUtil;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author zhanpu
 * @date 20-11-30
 */
@Getter
@Slf4j
class LockRenewal implements Runnable, Serializable {

    private static final long serialVersionUID = -8870471622258272462L;

    /**
     * key
     */
    private final String key;

    /**
     * value
     */
    private final String value;

    /**
     * 超时时间
     */
    private final long timeout;

    /**
     * RedisTemplate
     */
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 是否成功
     */
    private volatile boolean success = true;

    /**
     * 构造
     *
     * @param key
     * @param value
     * @param timeout
     * @param redisTemplate
     */
    public LockRenewal(String key, String value, long timeout, RedisTemplate<String, Object> redisTemplate) {
        this.key = key;
        this.value = value;
        this.timeout = timeout;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void run() {
        while (success) {
            try {
                //取超时时间的0.85倍时进行续期，节省cpu占用
                BigDecimal div = NumberUtil.div(TimeUnit.MILLISECONDS.convert(timeout, TimeUnit.SECONDS) + "", "0.85", 0);
                TimeUnit.MILLISECONDS.sleep(div.longValue());
                Long result = redisTemplate.execute(LuaScriptUtil.getLuaRenewalScript(), Collections.singletonList(key), value, timeout);

                if (Objects.nonNull(result) && result.compareTo(0L) != 0) {
                    log.debug("+++++续期成功+++++");
                } else {
                    log.debug("+++++续期失败+++++");
                    stop();
                }
            } catch (InterruptedException e) {
            } catch (Exception e) {
                log.error("+++++续期线程异常+++++", e);
            }
        }

        log.debug("+++++续期结束+++++");
    }

    /**
     * 停止
     */
    void stop() {
        success = false;
    }
}
